package com.wxy.ej.nosql.modules.collectiondata.repository;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.rt.easyjava.common.base.Result;
import org.apache.commons.lang.StringUtils;
import org.bson.Document;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Consumer;

@Repository
public class CollectionDataRepository {
    @Resource
    MongoTemplate mongoTemplate;

    public void saveJson(JSONObject jsonObject, String collectionName){
        jsonObject.put("createTime", DateUtil.now());
        mongoTemplate.save(jsonObject, collectionName);
    }

    public JSONObject queryByKey(String collectionName, String key, Object value){
        Query query=new Query(Criteria.where(key).is(value));
        List<JSONObject> list =  mongoTemplate.find(query, JSONObject.class, collectionName);
        if (list==null || list.size()==0) return null;
        return list.get(0);
    }

    public List query(String collectionName){
        //Query query=new Query(Criteria.where("_id").is(object.getId()));
        return mongoTemplate.find(new Query(),JSONObject.class, collectionName);//.sort({"_id":"-1"});
        //return mongoTemplate.getCollection("CollectionData").find();
    }

    public Result page(JSONObject queryJsonObject, String collectionName){
        int pageStart = queryJsonObject.getInteger("pageStart");
        int pageLimit = queryJsonObject.getInteger("pageLimit");

        Criteria criteria = new Criteria();
        // 忽略的参数
        List<String> ignoreList = new ArrayList<>();
        ignoreList.add("pageStart");
        ignoreList.add("pageLimit");
        ignoreList.add("route");
        ignoreList.add("urlQueryData");
        Iterator<String> it = queryJsonObject.keySet().iterator();
        List<QueryParam> queryParamList = new ArrayList<>();
        while (it.hasNext()) {
            String key = it.next();
            if (ignoreList.contains(key)) continue;
            String val = queryJsonObject.getString(key);
            if (val == null || val.trim().length() == 0) {
                continue;
            }
            String newKey = key;
            String link = "eq";
            // like 查询
            if (key.indexOf("like__")==0) {
                newKey = StringUtils.substringAfter(key, "like__");
                link = "like";
            }
            // gt 查询
            if (key.indexOf("gt__") == 0) {
                newKey = StringUtils.substringAfter(key, "gt__");
                link = "gt";
            }
            // gte 查询
            if (key.indexOf("gte__") == 0) {
                newKey = StringUtils.substringAfter(key, "gte__");
                link = "gte";
            }
            // lt_ 查询
            if (key.indexOf("lt__") == 0) {
                newKey = StringUtils.substringAfter(key, "lt__");
                link = "lt";
            }
            // lte_ 查询
            if (key.indexOf("lte__") == 0) {
                newKey = StringUtils.substringAfter(key, "lte__");
                link = "lte";
            }

            QueryParam queryParam = findObjByKey(queryParamList, newKey);
            if (queryParam!=null) {
                queryParam.setLink2(link);
                queryParam.setVal2(val);
                continue;
            }
            queryParam = new QueryParam();
            queryParam.setKey(newKey);
            queryParam.setLink1(link);
            queryParam.setVal1(val);
            queryParamList.add(queryParam);
        }

        for(QueryParam queryParam:queryParamList) {
            // eq 查询
            if (queryParam.getLink1().equalsIgnoreCase("eq")) {
                criteria.and(queryParam.getKey()).is(queryParam.getVal1());
            }
            // like 查询
            if (queryParam.getLink1().equalsIgnoreCase("like")) {
                criteria.and(queryParam.getKey()).regex(".*?" + queryParam.getVal1() + ".*", "i");
            }
            // 大于、小于
            if ((queryParam.getLink1()!=null && (queryParam.getLink1().indexOf("gt")==0 || queryParam.getLink1().indexOf("lt")==0))
                    || (queryParam.getLink2()!=null && (queryParam.getLink2().indexOf("gt")==0 || queryParam.getLink2().indexOf("lt")==0))) {
                Criteria c = criteria.and(queryParam.getKey());
                if (queryParam.getLink1()!=null) {
                    if (queryParam.getLink1().equalsIgnoreCase("gt")) {
                        c.gt(queryParam.getVal1());
                    }
                    if (queryParam.getLink1().equalsIgnoreCase("gte")) {
                        c.gte(queryParam.getVal1());
                    }
                    if (queryParam.getLink1().equalsIgnoreCase("lt")) {
                        c.lt(convertToEndDatetime(queryParam.getVal1()));
                    }
                    if (queryParam.getLink1().equalsIgnoreCase("lte")) {
                        c.lte(convertToEndDatetime(queryParam.getVal1()));
                    }
                }
                if (queryParam.getLink2()!=null) {
                    if (queryParam.getLink2().equalsIgnoreCase("gt")) {
                        c.gt(queryParam.getVal2());
                    }
                    if (queryParam.getLink2().equalsIgnoreCase("gte")) {
                        c.gte(queryParam.getVal2());
                    }
                    if (queryParam.getLink2().equalsIgnoreCase("lt")) {
                        c.lt(convertToEndDatetime(queryParam.getVal2()));
                    }
                    if (queryParam.getLink2().equalsIgnoreCase("lte")) {
                        c.lte(convertToEndDatetime(queryParam.getVal2()));
                    }
                }
            }
        }

        Query query=new Query(criteria);
        int total =  (int)mongoTemplate.count(query,JSONObject.class, collectionName);

        query.with(Sort.by(Sort.Direction.DESC, "_id"));
        query.skip(pageStart).limit(pageLimit);
        List list = mongoTemplate.find(query,JSONObject.class, collectionName);

        Result result = new Result();
        result.setList(list);
        result.setTotal(total);
        return result;
    }


    private QueryParam findObjByKey(List<QueryParam> queryParamList, String key) {
        for (QueryParam queryParam:queryParamList) {
            if (queryParam.getKey().equalsIgnoreCase(key)) {
                return queryParam;
            }
        }
        return null;
    }

    private static String convertToEndDatetime(Object dateObj) {
        if (dateObj==null) return null;
        String date = dateObj.toString();
        if (date==null) return date;
        date = date.trim();
        if (date.length()!=10)return date;
        try{
            DateUtil.parse(date, "yyyy-MM-dd");
        }catch (Exception e) {
            return date;
        }
        return date+" 23:59:59.999";
    }


    public Result pageMql(JSONObject queryJsonObject, String collectionName) {
        int pageStart = queryJsonObject.getInteger("pageStart");
        int pageLimit = queryJsonObject.getInteger("pageLimit");
        String mql = queryJsonObject.getString("mql");

        Document condition = new Document(JSONObject.parseObject(mql));
        MongoDatabase database = mongoTemplate.getMongoDbFactory().getMongoDatabase();
        MongoCollection<Document> mongoCollection =  database.getCollection(collectionName);

        //total
        int total = (int)mongoCollection.countDocuments(condition);

        // list
        FindIterable<Document>  rets = mongoCollection.find(condition).skip(pageStart).limit(pageLimit)
                .sort(new Document(JSONObject.parseObject("{'_id':-1}")));
        List<Document> list = new ArrayList<>();
        rets.forEach(new Consumer<Document>() {
            @Override
            public void accept(Document document) {
                list.add(document);
            }
        });
        System.out.println(list);
        return Result.builder(list).setTotal(total);
    }

}
